package com.leilei.sensitive;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.Objects;

/**
 * @author lei
 * @create 2024-05-20 14:13
 * @desc 数据脱敏JSON序列化实现
 **/
@Slf4j
public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer {

    private BeanProperty beanProperty;

    private SensitiveReplaceEnum sensitiveReplaceEnum;

    private Integer prefix;

    private Integer suffix;

    private String maskStr;

    public SensitiveJsonSerializer(BeanProperty beanProperty, SensitiveReplaceEnum sensitiveReplaceEnum,
                                   Integer prefix, Integer suffix, String maskStr) {
        this.beanProperty = beanProperty;
        this.sensitiveReplaceEnum = sensitiveReplaceEnum;
        this.prefix = prefix;
        this.suffix = suffix;
        this.maskStr = maskStr;
    }

    public SensitiveJsonSerializer() {
    }

    /**
     * 动态脱敏,替换数据序列化
     *
     * @param origin
     * @param jsonGenerator
     * @param serializerProvider
     * @return void
     * @author lei
     * @date 2024-05-20 15:37:37
     */
    @Override
    public void serialize(final String origin, final JsonGenerator jsonGenerator,
                          final SerializerProvider serializerProvider) throws IOException {
        if (origin == null || origin.isEmpty()) {
            jsonGenerator.writeString("");
            return;
        }
        String desensitize;
        if (SensitiveReplaceEnum.CUSTOMER.equals(sensitiveReplaceEnum)) {
            desensitize = SensitiveReplaceEnum.desensitizeValue(origin, prefix, suffix, maskStr);
        } else {
            desensitize = sensitiveReplaceEnum.desensitize(origin);
        }
        jsonGenerator.writeString(desensitize);
        if (SensitiveAutoConfiguration.printSensitiveLog && log.isDebugEnabled()) {
            String className = beanProperty.getMember().getDeclaringClass().getName();
            log.debug("[Sensitive] 脱敏字段: {} = {} → {}", className + "." + beanProperty.getName(), origin, desensitize);
        }
    }

    /**
     * 可以获得字段的类型以及注解
     * createContextual方法只会在第一次序列化字段时调用，因为字段的上下文信息在运行期不会改变
     *
     * @param serializerProvider
     * @param beanProperty
     * @return JsonSerializer<?>
     * @author lei
     * @date 2024-05-20 15:25:40
     */
    @Override
    public JsonSerializer<?> createContextual(final SerializerProvider serializerProvider,
                                              final BeanProperty beanProperty) throws JsonMappingException {
        if (beanProperty != null) {
            if (Objects.equals(beanProperty.getType().getRawClass(), String.class)) {
                // 尝试从需要解析的字段中读取脱敏注解
                Sensitive sensitive = beanProperty.getAnnotation(Sensitive.class);
                if (sensitive == null) {
                    sensitive = beanProperty.getContextAnnotation(Sensitive.class);
                }
                // 有注解则将注解属性填充至自定义序列化类
                if (sensitive != null) {
                    if (SensitiveAutoConfiguration.sensitiveEnable != null && SensitiveAutoConfiguration.sensitiveEnable.equals(Boolean.FALSE)) {
                        // 使用默认jackson序列化
                        return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
                    }
                    return new SensitiveJsonSerializer(beanProperty, sensitive.type(), sensitive.prefix(), sensitive.suffix(), sensitive.maskStr());
                }
            }
            // 使用默认jackson序列化
            return serializerProvider.findValueSerializer(beanProperty.getType(), beanProperty);
        }
        return serializerProvider.findNullValueSerializer(null);
    }
}
